package com.ryan.framework.dao;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;

import com.ryan.framework.model.Model;
import com.ryan.framework.tag.pagination.Page;

public interface BaseHibernateDao<M extends Model, PK extends Serializable> { 
    
	
	public Type getModelType();
	
	/**
	 * 获取session，事务必须是开启的(Required)，否则获取不到
	 * @return
	 */
	public Session getSession();
	
	/**
	 * 保存新增或修改的对象.
	 * 
	 * @param entity
	 * @return
	 */
	public M save(final M entity);

	/**
	 * 删除对象.
	 * 
	 * @param entity 对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final M entity);

	/**
	 * 按id删除对象.
	 */
	public void delete(final PK id);

	/**
	 * 按id获取对象，如果是复合主键，应该参照composite-id的方式创建主键对象.
	 */
	public M get(final PK id);
	
	/**
	 * 按id列表获取对象列表.
	 */
	public List<M> get(final Collection<PK> ids);
	
	/**
	 * 获取被数据库锁锁住的对象
	 * 
	 * @param id
	 * @return
	 */
	public M getForUpdate(final PK id);
	
	/**
	 * 刷新对象
	 * 
	 * @param object
	 * @return
	 */
	public M refresh(M entity);
	
	/**
	 *	获取全部对象.
	 */
	public List<M> getAll();
	
	/**
	 * 从session中清除此对象，使之成为游离状态
	 * 
	 * @param entity
	 */
	public void evict(M entity);
	
	/**
	 * 分页获取对象
	 * 
	 * @param page
	 * @return
	 */
	public List<M> getAll(Page page);

	/**
	 *	获取全部对象, 支持按属性行序.
	 */
	public List<M> getAll(String orderByProperty, boolean isAsc);

	/**
	 * 按属性查找对象列表, 匹配方式为相等.
	 */
	public List<M> findBy(final String propertyName, final Object value);

	/**
	 * 按属性查找唯一对象, 匹配方式为相等.如果结果不唯一，取第一条记录.
	 */
	public M findUniqueBy(final String propertyName, final Object value);

	/**
	 * 按HQL查询对象列表，一次查出所有数据，查询速度比对应的iterator方法高，但对于大数据量要求内存多.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @see #iterator(String, Object...)
	 */
	public <X> List<X> find(final String hql, final Object... values);
	
	/**
	 * 按HQL分页查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> List<X> find(final String hql, Page page, final Object... values);

	/**
	 * 按HQL查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 命名参数,按名称绑定.
	 * @see #iterator(String, Map)
	 */
	public <X> List<X> find(final String hql, final Map<String, ?> values);
	
	/**
	 * 按HQL查询返回对象迭代器，查询会发出N+1次查询，注意与对应find方法区分，当数据量较大时使用此方法.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @see #iterator(String, Map)
	 */
	public <X> Iterator<X> iterator(final String hql, final Map<String, ?> values);
	
	/**
	 * 按HQL分页查询对象列表.
	 * <pre>
	 * 根据hql中的查询表达式，返回的X对象可以是以下几种：Entity对象、Object[]、List或Map
	 * 比如：
	 * <li>String hql = "from Category c";</li>则返回Entity对象c
	 * <li>String hql = "select c.categoryId, c.name, c.description from Category c";</li>则返回Object[]
	 * <li>String hql = "select new List(c.categoryId, c.name, c.description) from Category c";</li>则返回List
	 * <li>String hql = "select new Map(c.categoryId as id, c.name as name, c.description as descn) from Category c";</li>则返回Map
	 * </pre>
	 * @param hql
	 * @param page
	 * @param values 命名参数,按名称绑定.
	 */
	public <X> List<X> find(final String hql, Page page, final Map<String, ?> values);

	/**
	 * 按HQL查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> X findUnique(final String hql, final Object... values);

	/**
	 * 按HQL查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param values 命名参数,按名称绑定.
	 */
	public <X> X findUnique(final String hql, final Map<String, ?> values);

	/**
	 * 按Criteria查询对象列表.
	 * 
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 */
	public List<M> find(final Criterion... criterions);
	
	/**
	 * 按Criteria查询对象有序列表.
	 * 
	 * @param orders
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 * @see org.hibernate.criterion.Order
	 */
	public List<M> find(final Order[] orders, final Criterion... criterions);
	
	/**
	 * 按Criteria分页查询对象列表.
	 * 
	 * @param page
	 * @param criterions 数量可变的Criterion.
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 */
	public List<M> find(Page page, final Criterion...criterions);
	
	/**
	 * 按Criteria分页查询对象列表，并排序.
	 * @param page 分页对象
	 * @param orders Order.asc(beanProperty)或者Order.desc(beanProperty)
	 * @param criterions
	 * @return
	 * @see org.hibernate.criterion.Restrictions
	 * @see org.hibernate.criterion.Order
	 */
	public List<M> find(Page page, final Order[] orders, final Criterion...criterions);

	/**
	 * 按Criteria查询唯一对象，如果结果不唯一，取第一条记录.
	 * 
	 * @param criterions 数量可变的Criterion.
	 */
	public M findUnique(final Criterion... criterions);
	
	/**
	 * 返回指定属性的求和结果
	 * 
	 * @param <X>
	 * @param propertyName 要求求和的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X sum(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的平均值
	 * 
	 * @param <X>
	 * @param propertyName 要求求平均值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X avg(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的最大值
	 * 
	 * @param <X>
	 * @param propertyName 要求求最大值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X max(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回指定属性的最小值
	 * 
	 * @param <X>
	 * @param propertyName 要求求最小值的属性名称
	 * @param criterions 限定条件
	 * @return
	 */
	public <X> X min(final String propertyName, final Criterion... criterions);
	
	/**
	 * 返回对象的记录总算
	 * 
	 * @param criterions 限定条件
	 * @return
	 */
	public long count(final Criterion... criterions);

	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,不包括定义在数据库中的存储过程或函数
	 * 
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，不包括数据库中的存储过程或函数
	 * @param page
	 * @param values 可变类型参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, Page page, final Object... values);
	
	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询,不包括定义在数据库中的存储过程或函数
	 *
	 * @param <X>
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的命名查询，不包括数据库中的存储过程或函数
	 * @param page
	 * @param values 命名参数
	 * @return
	 */
	public <X> List<X> findByNamedQuery(final String queryName, Page page, final Map<String, ?> values);

	/**
	 * 执行定义在&lt;sql-query&gt;或&lt;query&gt;中的update或delete命名查询,包括定义在数据库中的存储过程或函数.
	 * 
	 * @param queryName 定义在&lt;sql-query&gt;或&lt;query&gt;中的update或delete命名查询，包括数据库中的存储过程或函数
	 * @param values 可变类型参数
	 * @return
	 */
	public int executeNamedQuery(String queryName, Object... values);

	/**
	 * 执行一个update或者delete的native sql
	 * 
	 * @param nativeSql String
	 * @return int 执行的sql影响到的记录数.
	 */
	public int executeSqlUpdate(final String nativeSql, final Object... values);
	
	/**
	 * 执行一个select的native sql
	 * 
	 * @param <X>
	 * @param nativeSql
	 * @param values 参数按顺序绑定
	 * @return
	 */
	public <X> List<X> executeSql(final String nativeSql, final Object... values);

	/**
	 * 执行HQL进行修改/删除操作.
	 * 
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return 更新记录数.
	 */
	public int execute(final String hql, final Object... values);

	/**
	 * 执行HQL进行修改/删除操作.
	 * 
	 * @param values 命名参数,按名称绑定.
	 * @return 更新记录数.
	 */
	public int execute(final String hql, final Map<String, ?> values);

	/**
	 * 判断对象的属性值在数据库内是否唯一.
	 * 
	 * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
	 */
	public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue);

	/**
	 * 取得sequence的下一个值，此方法仅供Oracle DB使用.
	 * 
	 * @param sequenceName sequence名称
	 * @return
	 */
	public BigDecimal getSeqNextValue(String sequenceName);

    /*
	/** 
     *  
     * <br/>Description:根据传入的实体向数据库添加一条记录 
     *  
     * @author Eric 
     * @param obj 
     * @throws AppException 
     *//*  
    public void addObject(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:强制刷新Hibernate缓存提交数据更改操作 
     *  
     * @author Eric 
     * @return 
     * @version V1.0 
     *//*  
    public void dbFlush() throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体向数据库添加一条记录,返回插入记录的主键 
     *  
     * @author Eric 
     * @param obj 
     * @return 
     * @throws AppException 
     *//*  
    public String addObjectPK(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体从数据库删除一条记录 
     *  
     * @author Eric 
     * @param obj 
     * @throws AppException 
     *//*  
    public void deleteObject(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体与ID从数据库删除一条记录 
     *  
     * @author Eric 
     * @param cls 
     * @param id 
     * @throws AppException 
     *//*  
    @SuppressWarnings("rawtypes")  
    public void deleteObject(Class cls,Serializable id) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体修改数据库中一条记录 
     *  
     * @author Eric 
     * @param obj 
     * @throws AppException 
     *//*  
    public void updateObject(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体修改数据库中一条记录,返回更新记录的主键 
     *  
     * @author Eric 
     * @param obj 
     * @return 
     * @throws AppException 
     *//*  
    public String updateObjectPK(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入的实体添加或修改数据库中一条记录 
     *  
     * @author Eric 
     * @param obj 
     * @throws AppException 
     *//*  
    public void addOrUpdate(Object obj) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据ID返回一个对象 
     *  
     * @author Eric 
     * @param cls 
     * @param id 
     * @return 
     * @throws AppException 
     *//*  
    @SuppressWarnings("rawtypes")  
    public Object findObjectById(Class cls,Serializable id) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据实体返回一个集合 
     *  
     * @author Eric 
     * @param cls 
     * @return 
     * @throws AppException 
     *//*  
    @SuppressWarnings("rawtypes")  
    public List findAllData(Class cls) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据传入HQL语句返回一个集合(供DAO使用) 
     *  
     * @author Eric 
     * @param hql 
     * @return 
     * @throws AppException 
     *//*  
    @SuppressWarnings("rawtypes")  
    public List findHQLObject(String hql) throws AppException;
  
    *//** 
     *  
     * <br/>Description:按HQL提供者别名与条件查询集合 
     *  
     * @author Eric 
     * @param hqlProviderSet 
     * @param queryName 
     * @param paramMap 
     * @return 
     * @throws AppException 
     *//*  
    
    @SuppressWarnings("rawtypes") 
    public List findListByHqlName(IHqlProviderSet hqlProviderSet,String queryName,Map paramMap) throws AppException{  
        String hql;  
        try{  
            hql = hqlProviderSet.getHqlByQryName(queryName);  
            Query query = sessionFactory.getCurrentSession().createQuery(hql);  
            if(paramMap != null){  
                hqlArgs(paramMap,query);  
            }  
  
            return query.list();  
        }catch(Exception e){  
            throw new AppException("按HQL提供者别名与条件查询集合异常，请联系管理员！",e);  
        }  
    }  
  
    *//** 
     *  
     * <br/>Description:按HQL提供者别名、条件、分页信息查询集合 
     *  
     * @author Eric 
     * @param hqlProviderSet 
     * @param queryName 
     * @param paramMap 
     * @param page 
     * @return 
     * @throws AppException 
     *//*   
    
    @SuppressWarnings("rawtypes") 
    public List findListByHqlName(IHqlProviderSet hqlProviderSet,String queryName,Map paramMap,PageEntity page) throws AppException{  
        String hql;  
        try{  
            hql = hqlProviderSet.getHqlByQryName(queryName);  
  
            Query query = sessionFactory.getCurrentSession().createQuery(hql);  
  
            if(paramMap != null){  
                hqlArgs(paramMap,query);  
            }  
  
            query.setFirstResult((page.getPageNo() - 1) * page.getPageSize());  
            query.setMaxResults(page.getPageSize());  
  
            return query.list();  
        }catch(Exception e){  
            throw new AppException("按HQL提供者别名、条件、分页信息查询集合异常，请联系管理员！",e);  
        }  
    }  
  
    *//** 
     *  
     * <br/>Description:根据传入实体对象返回总记录数 
     *  
     * @author Eric 
     * @param cls 
     * @return 
     * @throws AppException 
     *//*  
    @SuppressWarnings("rawtypes")  
    public int findIntRowCountByHqlName(Class cls) throws AppException;
  
    *//** 
     *  
     * <br/>Description:根据HQL提供者别名与条件查询记录总数 
     *  
     * @author Eric 
     * @param hqlProviderSet 
     * @param queryName 
     * @param paramMap 
     * @return 
     * @throws AppException 
     *//*  
    
    @SuppressWarnings("rawtypes")  
    public int findIntRowCountByHqlName(IHqlProviderSet hqlProviderSet,String queryName,Map paramMap) throws AppException{  
        String hql;  
        try{  
            hql = hqlProviderSet.getHqlByQryName(queryName);  
            Query query = sessionFactory.getCurrentSession().createQuery(hql);  
            if(paramMap != null){  
                hqlArgs(paramMap,query);  
            }  
            List list = query.list();  
            int rowCount = ((Number) list.get(0)).intValue();  
            return rowCount;  
        }catch(Exception e){  
            throw new AppException("执行带参数的查询记录总数异常，请联系管理员！",e);  
        }  
    }  
  
    *//** 
     *  
     * <br/>Description:为Hibernate查询设置参数 
     *  
     * @author Eric 
     * @param argsMap 
     * @param query 
     *//*  
    @SuppressWarnings("rawtypes")  
    public void hqlArgs(Map argsMap,Query query);
  
*/
}
